// 引入axios
import axios from 'axios'
// 引入vuex的store
import store from '@/store'
// 引入element的通知组件
import { Message } from 'element-ui'
// 引入router路由模块
import router from '@/router'
// 引入qs
import qs from 'qs'
// 创建信号量，用于标记当前是否正在刷新token，默认为true
let loading = false
// 创建请求数组，用于接纳所有因为token过期而无法正常获取数据的请求
let requests = []

// 创建axios实例，并设置通用属性
const request = axios.create({
  // 超时时间 - 10s
  timeout: 10000,
  // 默认前缀
  baseURL: ''
})

// axios拦截器，在发起请求之前
request.interceptors.request.use(config => {
  // 根判断传入的 url 前缀，设置不同的 baseURL
  config.baseURL = /^\/front/.test(config.url) ? 'http://edufront.lagou.com' : 'http://eduboss.lagou.com'
  // 获取vuex-state-user
  const { user } = store.state
  // 判断是否存在存user和user.access_token是否为空
  if (user && user.access_token) {
    // 设置请求头
    config.headers.Authorization = user.access_token
  }
  // 返回新的配置对象
  return config
})

// 响应拦截器，在服务器响应请求后触发
request.interceptors.response.use(function (response) {
  // 响应成功触发 - 即状态码 2xx
  return response
}, function (error) {
  // 响应失败触发 - 即状态码非 2xx
  // 判断返回状态码，实现不同的功能
  if (error.response.status === 400) {
    // 使用element-ui组件
    Message.error('参数错误')
  } else if (error.response.status === 401) {
    // 我们只能处理 401 状态码，但是 401 也可能有两种情况：无token 和 token错误
    // - 1、无token信息（用户未登录）--> 带参数跳转回登陆页
    if (!store.state.user) {
      // 调用封装的跳回首页函数
      toLogin()
      return Promise.reject(error)
    }
    // 节流器 - 只允许一个请求可以更新token
    if (!loading) {
      loading = true
    } else {
      // 其他请求全部以函数的方式存储在requests数组中
      requests.push(() => {
        request(error.config)
      })
      return
    }
    // - 2、token过期或者错误
    // - 使用refresh_token获取新数据替换掉旧数据
    return request({
      method: 'post',
      url: '/front/user/refresh_token',
      data: qs.stringify({
        refreshtoken: store.state.user.refresh_token
      })
    }).then((res) => {
      // - 响应成功判断返回数据是否正常
      // - - 异常带参数跳回首页
      if (res.data.state !== 1) {
        store.commit('setUserInfo', null)
        toLogin()
        return Promise.reject(error)
      }
      // - - 正常则将新数据替换掉旧数据
      store.commit('setUserInfo', res.data)
      return request(error.config)
    }).catch((err) => {
      console.log(err)
    }).finally(() => {
      // finally在请求最后无论如何都要执行
      // - 重置信号量、执行数组中的每一个函数、最后清空数组
      loading = false
      requests.forEach((item) => item())
      requests = []
    })
  } else if (error.response.status === 403) {
    Message.error('您没有权限，请联系管理员')
  } else if (error.response.status === 404) {
    Message.error('您访问的资源不存在')
  } else if (error.response.status >= 500) {
    Message.error('请求超时')
  }
  // 将错误抛出
  return Promise.reject(error)
})

// 封装跳转回首页的函数
function toLogin () {
  router.push({
    name: 'login',
    query: {
      // 因为zaijs文件中不能直接使用route所以使用router.currentRoute.fullPath保存跳转前的路由地址
      go: router.currentRoute.fullPath
    }
  })
}
// 导出实例
export default request
